﻿using Dapper;
using Microsoft.EntityFrameworkCore;
using Publicuse.ExpressionTool.Visitor;
using Publicuse.Interface.Extend;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace Publicuse.Service.Extend
{
    public class BaseServiceExt : IBaseServiceExt
    {
        /// <summary>
        /// 
        /// </summary>
        protected ISqlSugarClient _Client { get; set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="context"></param>
        public BaseServiceExt(ISqlSugarClient client)
        {
            _Client = client;
            //调试SQL事件，可以删掉
            _Client.Aop.OnLogExecuting = (sql, pars) =>
            {
                Console.WriteLine($"当前执行Sql语句：{sql}");
            };
        }

        #region Query

        /// <summary>
        /// 主键查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        public T Find<T>(int id, out string msg) where T : class
        {
            msg = string.Empty;
            try
            {
                return _Client.Queryable<T>().InSingle(id);
            }
            catch (Exception ex)
            {
                msg = ex.Message;
                return default(T);
            }
        }

        /// <summary>
        /// 主键查询-异步版本
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<T> FindAsync<T>(int id) where T : class
        {
            return await _Client.Queryable<T>().InSingleAsync(id);
        }

        /// <summary>
        /// 不应该暴露给上端使用者，尽量少用
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        [Obsolete("尽量避免使用，using 带表达式目录树的代替")]
        public ISugarQueryable<T> Set<T>() where T : class
        {
            return _Client.Queryable<T>();
        }

        /// <summary>
        /// 条件查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="funcWhere"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        public ISugarQueryable<T> Query<T>(Expression<Func<T, bool>> funcWhere, out string msg) where T : class
        {
            msg = string.Empty;
            try
            {
                return _Client.Queryable<T>().Where(funcWhere);
            }
            catch (Exception ex)
            {
                msg = ex.Message;
                return default(ISugarQueryable<T>);
            }
        }

        /// <summary>
        /// 条件查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expression"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        public List<T> QueryBySql<T>(Expression<Func<T, bool>> expression, out string msg) where T : class
        {
            msg = string.Empty;
            try
            {
                List<T> list = new List<T>();
                ConditionBuilderVisitor visitor = new ConditionBuilderVisitor();
                visitor.Visit(expression);
                string condition = visitor.Condition();
                string sql = ConstantSqlString<T>.GetQuertSql(condition);
                list = _Client.Ado.SqlQuery<T>(sql);
                return list.Count() == 0 ? null : list;
            }
            catch (Exception ex)
            {
                msg = ex.Message;
                return default(List<T>);
            }
        }

        /// <summary>
        /// 条件查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="sql"></param>
        /// <param name="parameters"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        public List<T> Query<T>(string sql, object parameters, out string msg) where T : class
        {
            msg = string.Empty;
            try
            {
                return _Client.Ado.SqlQuery<T>(sql, parameters);
            }
            catch (Exception ex)
            {
                msg = ex.Message;
                return default(List<T>);
            }
        }

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="funcWhere"></param>
        /// <param name="pageSize"></param>
        /// <param name="pageIndex"></param>
        /// <param name="funcOrderby"></param>
        /// <param name="msg"></param>
        /// <param name="isAsc"></param>
        /// <returns></returns>
        public PagingData<T> QueryPage<T>(Expression<Func<T, bool>> funcWhere, int pageSize, int pageIndex, Expression<Func<T, object>> funcOrderby, out string msg, bool isAsc = true) where T : class
        {
            msg = string.Empty;
            try
            {
                var list = _Client.Queryable<T>();
                if (funcWhere != null)
                {
                    list = list.Where(funcWhere);
                }
                list = list.OrderByIF(true, funcOrderby, isAsc ? OrderByType.Asc : OrderByType.Desc);
                PagingData<T> result = new PagingData<T>()
                {
                    DataList = list.ToPageList(pageIndex, pageSize),
                    PageIndex = pageIndex,
                    PageSize = pageSize,
                    RecordCount = list.Count(),
                };
                return result;
            }
            catch (Exception ex)
            {
                msg = ex.Message;
                return default(PagingData<T>);
            }
        }
        #endregion

        #region Insert

        /// <summary>
        /// 新增数据-同步版本
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        public T Insert<T>(T t, out string msg) where T : class, new()
        {
            msg = string.Empty;
            try
            {
                return _Client.Insertable(t).ExecuteReturnEntity();
            }
            catch (Exception ex)
            {
                msg = ex.Message;
                return default(T);
            }
        }

        /// <summary>
        /// 新增数据-异步版本
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <returns></returns>
        public async Task<T> InsertAsync<T>(T t) where T : class, new()
        {
            return await _Client.Insertable(t).ExecuteReturnEntityAsync();
        }

        /// <summary>
        /// 批量新增-事务执行
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="tList"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        public async Task<bool> InsertList<T>(List<T> tList) where T : class, new()
        {
            return await _Client.Insertable(tList.ToList()).ExecuteCommandIdentityIntoEntityAsync();
        }
        #endregion

        #region Update
        /// <summary>
        /// 是没有实现查询，直接更新的,需要Attach和State
        /// 
        /// 如果是已经在context，只能再封装一个(在具体的service)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        public async Task<bool> UpdateAsync<T>(T t) where T : class, new()
        {
            if (t == null) throw new Exception("t is null");
            return await _Client.Updateable(t).ExecuteCommandHasChangeAsync();
        }

        public void Update<T>(List<T> tList, out string msg) where T : class, new()
        {
            msg = string.Empty;
            try
            {
                _Client.Updateable(tList).ExecuteCommand();
            }
            catch (Exception ex)
            {
                msg = ex.Message;
            }
        }

        #endregion

        #region Delete
        /// <summary>
        /// 先附加 再删除
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="t"></param>
        /// <param name="msg"></param>
        public void Delete<T>(T t, out string msg) where T : class, new()
        {
            msg = string.Empty;
            try
            {
                _Client.Deleteable(t).ExecuteCommand();
            }
            catch (Exception ex)
            {
                msg = ex.Message;
            }
        }

        /// <summary>
        /// 根据主键删除
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="pId"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        public bool Delete<T>(object pId, out string msg) where T : class, new()
        {
            msg = string.Empty;
            try
            {
                T t = _Client.Queryable<T>().InSingle(pId);
                return _Client.Deleteable<T>(t).ExecuteCommand() > 0;
            }
            catch (Exception ex)
            {
                msg = ex.Message;
                return false;
            }
        }

        public void Delete<T>(List<T> tList, out string msg) where T : class
        {
            msg = string.Empty;
            try
            {
                _Client.Deleteable(tList).ExecuteCommand();
            }
            catch (Exception ex)
            {
                msg = ex.Message;
            }
        }
        #endregion


        #region Other 
        public ISugarQueryable<T> ExcuteQuery<T>(string sql, out string msg) where T : class, new()
        {
            msg = string.Empty;
            try
            {
                return _Client.SqlQueryable<T>(sql);
            }
            catch (Exception ex)
            {
                msg = ex.Message;
                return default(ISugarQueryable<T>);
            }
        }

        /// <summary>
        /// 执行SQL非查询操作
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="parameters"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        public int ExcuteQuery(string sql, object parameters, out string msg)
        {
            msg = string.Empty;
            try
            {
                return _Client.Ado.ExecuteCommand(sql, parameters);
            }
            catch (Exception ex)
            {
                msg = ex.Message;
                return -1;
            }
        }

        /// <summary>
        /// 自定义操作
        /// </summary>
        /// <param name="action"></param>
        public void ExcuteCustom(Action<ISqlSugarClient> action, out string msg)
        {
            msg = string.Empty;
            try
            {
                action.Invoke(_Client);
            }
            catch (Exception ex)
            {
                msg = ex.Message;
            }
        }

        public void Dispose()
        {
            if (_Client != null)
            {
                _Client.Dispose();
            }
        }
        #endregion
    }
}
